#pragma once
#include <iostream>
#include <string>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include "SetNonBlock.hpp"
const int backlog = 5; // 别的文件也要访问
#define CONV(addr_ptr) ((sockaddr *)(addr_ptr))
// 设计模式：模版方法类
class Socket
{
public:
    virtual ~Socket() {}
    virtual void CreateSocket() = 0;
    virtual void BindSocket(uint16_t port) = 0;
    virtual void ListenSocket(int backlog) = 0;
    virtual int AcceptConnection(std::string *peerip, uint16_t *peerport) = 0;
    virtual bool ConnectServer(std::string &serverip, uint16_t serverport) = 0;
    virtual int GetSockfd() = 0;
    virtual void SetSockfd(int sockfd) = 0;
    virtual void CloseSockfd() = 0;
    virtual bool Recv(std::string* buffer, int size) = 0;
    virtual void Send(std::string& message) = 0;
    virtual void ReuseAddr() = 0;
public:
    void BuildListenSocket(uint16_t port, int backlog) // 给服务器用的
    {
        CreateSocket();
        ReuseAddr();
        BindSocket(port);
        ListenSocket(backlog);
    }
    bool BuildConnectSocket(std::string &serverip, uint16_t serverport) // 给客户端用的
    {
        CreateSocket();
        return ConnectServer(serverip, serverport);
    }
    void BuildNormalSocket(int sockfd)
    {
        SetSockfd(sockfd);
    }
};

class TcpSocket : public Socket
{
public:
    TcpSocket(int sockfd)
        : _sockfd(sockfd)
    {
    }
    TcpSocket() {}
    ~TcpSocket() {}

    void CreateSocket() override
    {
        _sockfd = socket(AF_INET, SOCK_STREAM, 0);
        if (_sockfd < 0)
            exit(1);
        SetNonBlock(_sockfd);
    }
    void BindSocket(uint16_t port) override
    {
        sockaddr_in local;
        local.sin_family = AF_INET;
        local.sin_addr.s_addr = INADDR_ANY;
        local.sin_port = htons(port);

        int n = bind(_sockfd, CONV(&local), sizeof local);
        if (n < 0)
            exit(2);
    }
    void ListenSocket(int backlog) override
    {
        int n = listen(_sockfd, backlog);
        if (n < 0)
            exit(3);
        lg.LogMessage(Info, "Listen create success sockfd: %d\n", _sockfd);
    }

    int AcceptConnection(std::string *peerip, uint16_t *peerport) override
    {
        sockaddr_in peer;
        socklen_t len = sizeof peer;
        int newsockfd = accept(_sockfd, CONV(&peer), &len);
        if (newsockfd < 0)
            return -1;

        char peeripbuffer[64];
        inet_ntop(AF_INET, &peer.sin_addr, peeripbuffer, sizeof peeripbuffer - 1);
        *peerip = peeripbuffer;
        *peerport = ntohs(peer.sin_port);

        return newsockfd;
    }

    bool ConnectServer(std::string &serverip, uint16_t serverport) override
    {
        sockaddr_in server;
        server.sin_family = AF_INET;
        inet_pton(AF_INET, serverip.c_str(), &server.sin_addr.s_addr);
        server.sin_port = htons(serverport);

        int n = connect(_sockfd, CONV(&server), sizeof server);
        return n == 0 ? true : false;
    }

    int GetSockfd() override
    {
        return _sockfd;
    }

    void SetSockfd(int sockfd) override
    {
        _sockfd = sockfd;
    }

    void CloseSockfd() override
    {
        close(_sockfd);
    }
    bool Recv(std::string* buffer, int size) override
    {
        char inbuffer[size];
        int n = recv(_sockfd, inbuffer, size - 1, 0);
        // int n = recv(_sockfd, buffer, size - 1, 0); //找到了
        if(n > 0)
        {
            inbuffer[n] = 0;
            *buffer += inbuffer;
            return true;
        }
        else return false;
    }
    void Send(std::string& message) override
    {
        send(_sockfd, message.c_str(), message.size(), 0);
    }
    void ReuseAddr() override
    {
        int opt = 1;
        setsockopt(_sockfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof opt);
    }
private:
    int _sockfd;
};